use crate::{error::ApiError, yjson, ypath, yquery};
use axum::extract::{FromRequest, FromRequestParts};

#[derive(Debug, Clone, Copy, Default, FromRequest, FromRequestParts)]
#[from_request(via(axum_valid::Valid), rejection(ApiError))]
pub struct Valid<T>(pub T);

#[derive(Debug, Clone, Default)]
pub struct ValidQuery<T>(pub T);

#[derive(Debug, Clone, Default)]
pub struct ValidPath<T>(pub T);

#[derive(Debug, Clone, Default)]
pub struct ValidJson<T>(pub T);

// impl<S, T> FromRequestParts<S> for ValidQuery<T>
// where
//   S: Send + Sync,
//   yquery::Query<T>:
//     FromRequestParts<S, Rejection = ApiError> + axum_valid::HasValidate,
//   <yquery::Query<T> as axum_valid::HasValidate>::Validate: validator::Validate,
// {
//   type Rejection = ApiError;
//
//   async fn from_request_parts(
//     parts: &mut axum::http::request::Parts,
//     state: &S,
//   ) -> Result<Self, Self::Rejection> {
//     let result =
//       axum_valid::Valid::<yquery::Query<T>>::from_request_parts(parts, state)
//         .await?;
//     Ok(ValidQuery(result.0.0))
//   }
// }

impl<S, T> FromRequestParts<S> for ValidQuery<T>
where
  S: Send + Sync,
  Valid<yquery::Query<T>>: FromRequestParts<S, Rejection = ApiError>,
{
  type Rejection = ApiError;

  async fn from_request_parts(
    parts: &mut axum::http::request::Parts,
    state: &S,
  ) -> Result<Self, Self::Rejection> {
    let result = Valid::from_request_parts(parts, state).await?;
    Ok(ValidQuery(result.0.0))
  }
}

impl<S, T> FromRequest<S> for ValidJson<T>
where
  S: Send + Sync,
  Valid<yjson::Json<T>>: FromRequest<S, Rejection = ApiError>,
{
  type Rejection = ApiError;
  async fn from_request(
    req: axum::extract::Request,
    state: &S,
  ) -> Result<Self, Self::Rejection> {
    let result = Valid::from_request(req, state).await?;
    Ok(ValidJson(result.0.0))
  }
}

impl<S, T> FromRequestParts<S> for ValidPath<T>
where
  S: Send + Sync,
  Valid<ypath::Path<T>>: FromRequestParts<S, Rejection = ApiError>,
{
  type Rejection = ApiError;

  async fn from_request_parts(
    parts: &mut axum::http::request::Parts,
    state: &S,
  ) -> Result<Self, Self::Rejection> {
    let result = Valid::from_request_parts(parts, state).await?;
    Ok(ValidPath(result.0.0))
  }
}

// 可以通过声明宏来重构这里
